#
# This fragment implements testbench simulation using iVerilog.
#
# $Copyright: (c) 2009 Thomas Dejanovic $
#


targets ::
	@echo
	@echo "iverilog.mak:"
	@echo "-----------"
	@echo
	@echo
	@echo


IVERILOG_INCLUDED   = 1

#---------------------------------------------------------------------

%.hex : %.hex.gz
	gunzip -c $*.hex.gz > $*.hex

COMPRESSED_VECTOR_FILES   = $(wildcard *.hex.gz)
UNCOMPRESSED_VECTOR_FILES = $(COMPRESSED_VECTOR_FILES:%.hex.gz= %.hex)

clobber ::
	rm -f ${UNCOMPRESSED_VECTOR_FILES}

#---------------------------------------------------------------------
#
#
#

IVERILOG_RTL     := $(foreach dir,$(VERILOG_MODULE_DIRS),$(wildcard $(dir)/*.v))
IVERILOG_INCLUDE := $(foreach dir,$(VERILOG_MODULE_DIRS),$(wildcard $(dir)/*.vh))
IVERILOG_RTL     += ${IVERILOG_INCLUDE}


VERILOG_MODULE_DIRS += .


IVERILOG_DEPENDS = ${IVERILOG_RTL} ${VERILOG_DEPENDS}


IVERILOG_TESTBENCHES = $(wildcard test_*.v *_test.v)


IVERILOG_TESTS = $(IVERILOG_TESTBENCHES:%.v=%)


IVERILOG = iverilog -gspecify -D IVERILOG -v \
		$(VERILOG_MODULE_DIRS:%=-y %) \
		$(VERILOG_MODULE_DIRS:%=-I %) \
		$(VERILOG_LIBRARY_DIRS:%=-y %) \
		${VERILOG_LIBRARY_FILES}


IVERILOG_NETLIST = iverilog -gspecify -D IVERILOG -D NETLIST_SIM -v \
		$(VERILOG_NETLIST_DIRS:%=-y %) \
		$(VERILOG_NETLIST_DIRS:%=-I %) \
		$(VERILOG_MODULE_DIRS:%=-y %) \
		$(VERILOG_MODULE_DIRS:%=-I %) \
		$(VERILOG_LIBRARY_DIRS:%=-y %) \
		${VERILOG_LIBRARY_FILES}


IVERILOG_VHDL = iverilog -gspecify -D IVERILOG -v -D VHDL -pdepth=1 \
		$(VERILOG_BLACK_BOX_DIRS:%=-y %) \
		$(VERILOG_BLACK_BOX_DIRS:%=-I %) \
		$(VERILOG_MODULE_DIRS:%=-y %) \
		$(VERILOG_MODULE_DIRS:%=-I %) \
		$(VERILOG_LIBRARY_DIRS:%=-y %) \
		${VERILOG_LIBRARY_FILES}


#---------------------------------------------------------------------
#
# build log file error filters.
#

# things to loog for in the iverilog build log.

IVERILOG_BUILD_LOG_ERRORS  ="error|bits of the port unconnected|expects .+ bits, got .+|VHDL conversion error"

define CHECK_IVERILOG_BUILD_LOG
	@ if [ ! -f $@.build_log ] ; then \
	    echo "*** ERROR - log file $@.build_log not found." ;\
	    false ; \
	elif egrep -s ${IVERILOG_BUILD_LOG_ERRORS} $@.build_log > /dev/null ; then \
	    echo "*** ERROR - fatal errors in build log file." ;\
	    false ; \
	fi
endef


# things to look for in the iverilog simulation log.

IVERILOG_LOG_ERRORS ='ERROR | FAIL|Timing Violation'

define CHECK_IVERILOG_LOG
	@ if [ ! -f $@_fail ] ; then \
	    echo "*** ERROR - log file $@_fail not found." ;\
	    false ; \
	elif egrep -s ${IVERILOG_LOG_ERRORS} $@_fail > /dev/null ; then \
	    false ; \
	fi
endef

# grungy hack for simulation to allow X's -> known values which
# generate timing violations not cause the simualtion to fail.  This
# is so bad as to make automated netlist simualtion almost useless, so
# I need a more sophisticated check here.

IVERILOG_NETLIST_LOG_ERRORS ='ERROR | FAIL'

define CHECK_IVERILOG_NETLIST_LOG
	@ if [ ! -f $@_fail ] ; then \
	    echo "*** ERROR - log file $@_fail not found." ;\
	    false ; \
	elif egrep -s ${IVERILOG_NETLIST_LOG_ERRORS} $@_fail > /dev/null ; then \
	    false ; \
	fi
endef

#----------------------------------------------------------------------
#
# build and run iverilog without generating a dump file - regression mode.
#

.PRECIOUS: %.no_vcd
%.no_vcd : ${IVERILOG_DEPENDS} %.v
	rm -f $@ $@_fail $@.build_log
	${IVERILOG} -D NO_VCD $*.v -o $@_fail 2>&1 | tee $@.build_log
	${CHECK_IVERILOG_BUILD_LOG}
	mv $@_fail $@

.PRECIOUS: %.no_vcd_log
%.no_vcd_log : %.no_vcd
	rm -f $@ $@_fail
	time ./$*.no_vcd 2>&1 | tee $@_fail
	${CHECK_IVERILOG_LOG}
	mv $@_fail $@

.PHONY: %.test
%.test : %.no_vcd_log

.PHONY: test
test : $(IVERILOG_TESTS:%=%.no_vcd_log)

clobber ::
	rm -f *.no_vcd_fail *.no_vcd.build_log *.no_vcd 
	rm -f *.no_vcd_log_fail *.no_vcd_log

#----------------------------------------------------------------------
#
# build and run iverilog while generating a dump file - debug mode.
#

.PRECIOUS: %.dump_vcd
%.dump_vcd : ${IVERILOG_DEPENDS} %.v
	rm -f $@ $@_fail $@.build_log
	${IVERILOG} -D VCD $*.v -o $@_fail 2>&1 | tee $@.build_log
	${CHECK_IVERILOG_BUILD_LOG}
	mv $@_fail $@

.PRECIOUS: %.dump_vcd_log
%.dump_vcd_log : %.dump_vcd
	rm -f $@ $@_fail $*.vcd
	time ./$*.dump_vcd 2>&1 | tee $@_fail
	# ${CHECK_IVERILOG_LOG}
	mv $@_fail $@

.PHONY: %.view
%.view : %.dump_vcd_log
	gtkwave --dump=$*.vcd --save=$*.sav

.PHONY: vcd
vcd : $(IVERILOG_TESTS:%=%.dump_vcd_log) 

.PHONY: view
view : $(IVERILOG_TESTS:%=%.view)

clobber ::
	rm -f *.dump_vcd_fail *.dump_vcd.build_log *.dump_vcd 
	rm -f *.dump_vcd_log_fail *.dump_vcd_log *.vcd

#----------------------------------------------------------------------
#
# build and run iverilog on netlist without generating a dump file - regression mode
#

.PRECIOUS: %.netlist_no_vcd
%.netlist_no_vcd : ${IVERILOG_DEPENDS} %.v
	rm -f $@ $@_fail $@.build_log
	${IVERILOG_NETLIST} -D NO_VCD -D NETLIST_SIM $*.v -o $@_fail 2>&1 | tee $@.build_log
	${CHECK_IVERILOG_BUILD_LOG}
	mv $@_fail $@

.PRECIOUS: %.netlist_no_vcd_log
%.netlist_no_vcd_log : %.netlist_no_vcd
	rm -f $@ $@_fail
	time ./$*.netlist_no_vcd 2>&1 | tee $@_fail
	${CHECK_IVERILOG_NETLIST_LOG}
	mv $@_fail $@

.PHONY: %.netlist_test
%.netlist_test : %.netlist_no_vcd_log

.PHONY: nelist_test
test : $(IVERILOG_TESTS:%=%.netlist_no_vcd_log)

clobber ::
	rm -f *.netlist_no_vcd_fail *.netlist_no_vcd.build_log *.netlist_no_vcd 
	rm -f *.no_vcd_log_fail *.no_vcd_log

#----------------------------------------------------------------------
#
# build and run iverilog on netlist while generating a dump file - debug mode.
#

.PRECIOUS: %.netlist_dump_vcd
%.netlist_dump_vcd : ${IVERILOG_DEPENDS} %.v
	rm -f $@ $@_fail $@.build_log
	${IVERILOG_NETLIST} -D VCD -D NETLIST_SIM $*.v -o $@_fail 2>&1 | tee $@.build_log
	${CHECK_IVERILOG_BUILD_LOG}
	mv $@_fail $@

.PRECIOUS: %.netlist_dump_vcd_log
%.netlist_dump_vcd_log : %.netlist_dump_vcd
	rm -f $@ $@_fail $*.vcd
	time ./$*.netlist_dump_vcd 2>&1 | tee $@_fail
	# ${CHECK_IVERILOG_NETLIST_LOG}
	mv $@_fail $@

.PHONY: %.netlist_view
%.netlist_view : %.netlist_dump_vcd_log
	gtkwave --dump=$*.netlist_vcd --save=$*.sav

.PHONY: netlist_vcd
netlist_vcd : $(IVERILOG_TESTS:%=%.netlist_vcd_log) 

.PHONY: netlist_view
view : $(IVERILOG_TESTS:%=%.netlist_view)

clobber ::
	rm -f *.netlist_dump_vcd_fail *.netlist_dump_vcd.netlist_build_log *.netlist_dump_vcd 
	rm -f *.netlist_dump_vcd_log_fail *.netlist_dump_vcd_log *.netlist_vcd

#----------------------------------------------------------------------

# VHDL generation.

LOCAL_VERILOG = $(wildcard ${MODULE}*.v)

LOCAL_VHDL = $(LOCAL_VERILOG:%.v=%.vhd)

.PHONY: vhdl
vhdl : ${LOCAL_VHDL}

%.vhd : %.v
	rm -f $@_fail $@ $@.build_log
	${IVERILOG_VHDL} $*.v -o $@_fail -tvhdl 2>&1 | tee $@.build_log
	${CHECK_IVERILOG_BUILD_LOG}
	# hack to deal with problematic port types :-|
	replaceAll ": buffer " ": out " $@_fail
	mv $@_fail $@

clobber ::
	rm -f *.vhd_fail *.vhd *.vhd.build_log

#----------------------------------------------------------------------

# EDIF generation - does not currently work with iverilog 0.9

LOCAL_VERILOG = $(wildcard *.v)

LOCAL_EDIF = $(LOCAL_VERILOG:%.v=%.edif)

.PHONY: edif
edif : ${LOCAL_EDIF}

%.edif : %.v
	rm -f $@_fail $@ $@.build_log
	${IVERILOG} -D NO_VCD $*.v -o $@_fail -tfpga 2>&1 | tee $@.build_log
	${CHECK_IVERILOG_BUILD_LOG}
	mv $@_fail $@

clobber ::
	rm -f *.edif_fail *.edif *.edif.build_log


#----------------------------------------------------------------------
# Local Variables:
# mode: makefile
# End:
# End of iverilog.mak
